package me.zhengjie.modules.quartz.task;

import cn.hutool.core.date.DateTime;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.fund.domain.StockNetValue;
import me.zhengjie.modules.fund.domain.UserStockLog;
import me.zhengjie.modules.fund.repository.UserStockLogRepository;
import me.zhengjie.modules.fund.reptile.StockCrawler;
import me.zhengjie.modules.fund.service.StockNetValueService;
import me.zhengjie.modules.fund.service.UserStockService;
import me.zhengjie.modules.fund.service.dto.UserStockDto;
import me.zhengjie.modules.fund.service.dto.UserStockQueryCriteria;
import me.zhengjie.utils.DateUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 用户股票净值更新任务
 * 每晚更新用户的股票净值
 */
@Slf4j
@Component
public class UserStockNetValueUpdateTask {

    @Resource
    private UserStockService userStockService;

    @Resource
    private StockCrawler stockCrawler;

    @Resource
    private StockNetValueService stockNetValueService;

    @Resource
    private UserStockLogRepository userStockLogRepository;

    public void run() throws ParseException, IOException {
        int pageNum = 0;
        int pageSize = 100;
        Page<UserStockDto> pageUserStocks;
        do {
            PageRequest page = PageRequest.of(pageNum, pageSize, Sort.Direction.DESC, "id");
            pageUserStocks = userStockService.queryAll(new UserStockQueryCriteria(), page);

            List<UserStockDto> userFunds = pageUserStocks.getContent();
            try {
                syncStockNetValues(userFunds);
            } catch (ParseException | IOException e) {
                log.error("同步股票净值失败", e);
                throw e;
            }
            pageNum++;
        } while (pageUserStocks.hasNext());

        // 写日志
        generateLog();
    }

    @Transactional(rollbackFor = Exception.class)
    public void syncStockNetValues(List<UserStockDto> userStockDtos) throws ParseException, IOException {
        if (CollectionUtils.isEmpty(userStockDtos)) {
            return;
        }
        for (UserStockDto userStockDto : userStockDtos) {
            if ("合计".equals(userStockDto.getStockName())) {
                continue;
            }

            // 获取最新的数据，并插入到数据库中
            List<StockNetValue> lastedNetValues = stockCrawler.getLastedNetValues(userStockDto.getStockCode());
            if (CollectionUtils.isEmpty(lastedNetValues)) {
                continue;
            }
            stockNetValueService.save(lastedNetValues);
            userStockService.updateNetValue(lastedNetValues.get(0));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void generateLog() throws ParseException, IOException {
        int pageNum = 0;
        int pageSize = 100;

        DateTime yesterday = me.zhengjie.utils.DateUtil.getYesterdayDate();
        DateTime theDayBeforeYesterdayDate = DateUtil.getTheDayBeforeYesterdayDate();

        Page<UserStockDto> pageUserStocks;
        do {
            PageRequest page = PageRequest.of(pageNum, pageSize, Sort.Direction.DESC, "id");
            pageUserStocks = userStockService.queryAll(new UserStockQueryCriteria(), page);

            List<UserStockDto> userStockDtos = pageUserStocks.getContent();
            saveUserStockLog(userStockDtos, yesterday, theDayBeforeYesterdayDate);
            pageNum++;
        } while (pageUserStocks.hasNext());
    }

    private void saveUserStockLog(List<UserStockDto> userStockDtos, Date yesterday, Date theDayBeforeYesterday) {

        for (UserStockDto userStockDto : userStockDtos) {
            if (userStockDto.getStockName().equals("合计")) {
                continue;
            }
            UserStockLog userStockLog = new UserStockLog();
            userStockLog.setDate(yesterday);
            userStockLog.setUserId(userStockDto.getUserId());
            userStockLog.setStockCode(userStockDto.getStockCode());
            userStockLog.setStockName(userStockDto.getStockName());
            userStockLog.setCount(userStockDto.getCount());
            userStockLog.setNewestAmount(userStockDto.getNewestAmount());
            userStockLog.setNewestNetValue(userStockDto.getNewestNetValue());
            userStockLog.setNewestUpdatedDate(userStockDto.getNewestUpdatedDate());
            userStockLog.setPrincipalAmount(userStockDto.getPrincipalAmount());
            userStockLog.setPrincipalNetValue(userStockDto.getPrincipalNetValue());
            userStockLog.setPurchaseChannel(userStockDto.getPurchaseChannel());

            // 昨天日志
            UserStockLog theDayBeforeYesterdayLog = userStockLogRepository.findByUserIdAndStockCodeAndDate(userStockDto.getUserId(), userStockDto.getStockCode(), theDayBeforeYesterday);
            if (Objects.nonNull(theDayBeforeYesterdayLog)) {
                // 盈利金额 = 当前最新金额 + 在途金额 - 昨日金额
                userStockLog.setProfitAmount(userStockLog.getNewestAmount().subtract(theDayBeforeYesterdayLog.getNewestAmount()));
                userStockLog.setProfitRate(userStockLog.getProfitAmount().divide(theDayBeforeYesterdayLog.getNewestAmount(), 4, BigDecimal.ROUND_HALF_UP));
            }

            UserStockLog exists = userStockLogRepository.findByUserIdAndStockCodeAndDate(userStockLog.getUserId(), userStockLog.getStockCode(), userStockLog.getDate());
            if (Objects.isNull(exists)) {
                userStockLogRepository.save(userStockLog);
            } else {
                userStockLog.setId(exists.getId());
                userStockLogRepository.save(userStockLog);
            }
        }
    }
}
